<template>
  <div class="measure-tool">
    <div class="button-container">
      <div class="ol-control distance-button">
        <button @click="measure('distance')">距离</button>
      </div>
      <div class="ol-control area-button">
        <button @click="measure('area')">面积</button>
      </div>
      <div class="ol-control angle-button">
        <button @click="measure('angle')">角度</button>
      </div>
      <div class="ol-control clear-button">
        <button @click="clearAllMeasurements">清除</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onBeforeUnmount } from 'vue';
import { Draw } from "ol/interaction";
import { Vector as VectorSource } from "ol/source";
import { Vector as VectorLayer } from "ol/layer";
import Overlay from 'ol/Overlay';
import { LineString } from 'ol/geom';
import { unByKey } from 'ol/Observable';
import { getLength, getArea } from 'ol/sphere';
import Style from "ol/style/Style";
import Stroke from "ol/style/Stroke";
import Fill from "ol/style/Fill";
import Circle from "ol/style/Circle";

// 使用 defineProps 接收父组件传来的 map 对象
const props = defineProps({
  map: Object
});

// 使用 ref 和 reactive 创建响应式状态
const measureType = ref("distance");
const draw = ref(null);
const vectorLayer = ref(null);
const measureResult = ref("0");
const measurementResults = reactive({}); // 存储所有测量结果的数值

// 将原 data 中非响应式的临时变量定义为 let
let tipDiv = null;
let pointermoveEvent = null;
let sketchFeature = null;
let geometryListener = null;

const creatDraw = (type) => {
  if (!props.map) return;

  const maxPoints = measureType.value === "angle" ? 3 : null;

  if (!vectorLayer.value) {
    let vectorSource = new VectorSource({ wrapX: false });
    vectorLayer.value = new VectorLayer({
      source: vectorSource,
      style: new Style({
        fill: new Fill({ color: 'rgba(252, 86, 49, 0.1)' }),
        stroke: new Stroke({ color: '#fc5531', width: 3 }),
        image: new Circle({ radius: 0, fill: new Fill({ color: '#fc5531' }) })
      }),
      name: "测量图层"
    });
    props.map.addLayer(vectorLayer.value);
  }

  draw.value = new Draw({
    source: vectorLayer.value.getSource(),
    type: type,
    maxPoints: maxPoints,
    style: new Style({
      fill: new Fill({ color: 'rgba(252, 86, 49, 0.1)' }),
      stroke: new Stroke({ color: '#fc5531', lineDash: [10, 10], width: 3 }),
      image: new Circle({ radius: 0, fill: new Fill({ color: '#fc5531' }) })
    }),
    condition: (evt) => {
      if (measureResult.value !== "0" && !props.map.getOverlayById(measureResult.value) && measureType.value === "distance") {
        creatMark(null, measureResult.value, measureResult.value).setPosition(evt.coordinate);
      }
      return true;
    }
  });
  props.map.addInteraction(draw.value);

  draw.value.on("drawstart", e => {
    sketchFeature = e.feature;
    const proj = props.map.getView().getProjection();

    if (measureType.value === "distance") {
      creatMark(null, "起点", "start").setPosition(props.map.getCoordinateFromPixel(e.target.downPx_));
      tipDiv.innerHTML = "总长：0 m</br>单击确定地点，双击结束";
      geometryListener = sketchFeature.getGeometry().on('change', (evt) => {
        measureResult.value = distanceFormat(getLength(evt.target, { "projection": proj, "radius": 6378137 }));
        tipDiv.innerHTML = "总长：" + measureResult.value + "</br>单击确定地点，双击结束";
        measurementResults[measureType.value] = measureResult.value;
      });
    } else if (measureType.value === "area") {
      tipDiv.innerHTML = "面积：0 m<sup>2</sup></br>继续单击确定地点";
      geometryListener = sketchFeature.getGeometry().on('change', (evt) => {
        if (evt.target.getCoordinates()[0].length < 4) {
          tipDiv.innerHTML = "面积：0m<sup>2</sup></br>继续单击确定地点";
        } else {
          measureResult.value = formatArea(getArea(evt.target, { "projection": proj, "radius": 6378137 }));
          tipDiv.innerHTML = "面积：" + measureResult.value + "</br>单击确定地点，双击结束";
          measurementResults[measureType.value] = measureResult.value;
        }
      });
    } else if (measureType.value === "angle") {
      tipDiv.innerHTML = "继续单击确定顶点";
      geometryListener = sketchFeature.getGeometry().on('change', (evt) => {
        if (evt.target.getCoordinates().length < 3) {
          tipDiv.innerHTML = "继续单击确定顶点";
        } else {
          measureResult.value = formatAngle(evt.target);
          tipDiv.innerHTML = "角度：" + measureResult.value + "</br>继续单击结束";
          measurementResults[measureType.value] = measureResult.value;
        }
      });
    }
  });

  draw.value.on("drawend", e => {
    const closeBtn = document.createElement('span');
    closeBtn.innerHTML = "×";
    closeBtn.title = "清除测量";
    closeBtn.style = "width: 10px;height:10px;line-height: 12px;text-align: center;border-radius: 5px;display: inline-block;padding: 2px;color: rgb(255, 68, 0);border: 2px solid rgb(255, 68, 0);background-color: rgb(255, 255, 255);font-weight: 600;position: absolute;top: -25px;right: -2px;cursor: pointer;";
    closeBtn.addEventListener('click', clearMeasure); // 使用重构后的函数

    if (measureType.value === "distance") {
      creatMark(closeBtn, null, "close1").setPosition(e.feature.getGeometry().getLastCoordinate());
      creatMark(null, "总长：" + measurementResults[measureType.value] + "", "length").setPosition(e.feature.getGeometry().getLastCoordinate());
      props.map.removeOverlay(props.map.getOverlayById(measureResult.value));
    } else if (measureType.value === "area") {
      creatMark(closeBtn, null, "close2").setPosition(e.feature.getGeometry().getInteriorPoint().getCoordinates());
      creatMark(null, "总面积：" + measurementResults[measureType.value] + "", "area").setPosition(e.feature.getGeometry().getInteriorPoint().getCoordinates());
    } else if (measureType.value === "angle") {
      creatMark(closeBtn, null, "close3").setPosition(e.feature.getGeometry().getCoordinates()[1]);
      creatMark(null, "角度：" + measurementResults[measureType.value] + "", "angle").setPosition(e.feature.getGeometry().getCoordinates()[1]);
    }
    stopMeasure();
  });
};

const measure = (type) => {
  if (!props.map) return;

  if (draw.value && draw.value.getActive()) {
    draw.value.setActive(false);
  }
  measureType.value = type;
  tipDiv = document.createElement('div');
  tipDiv.innerHTML = '单击确定起点';
  tipDiv.className = "tipDiv";
  tipDiv.style = "width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;";

  const overlay = new Overlay({
    element: tipDiv,
    autoPan: false,
    positioning: "bottom-center",
    id: "tipLay",
    stopEvent: false
  });
  props.map.addOverlay(overlay);
  pointermoveEvent = props.map.on("pointermove", evt => {
    overlay.setPosition(evt.coordinate);
  });

  if (type === 'distance' || type === 'angle') {
    creatDraw('LineString');
  } else if (type === 'area') {
    creatDraw('Polygon');
  }
};

const creatMark = (markDom, txt, idstr) => {
  if (!markDom) {
    markDom = document.createElement('div');
    markDom.innerHTML = txt;
    markDom.style = "width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;";
  }
  const overlay = new Overlay({
    element: markDom,
    autoPan: false,
    positioning: "bottom-center",
    id: idstr,
    stopEvent: false
  });
  props.map.addOverlay(overlay);
  return overlay;
};

const distanceFormat = (length) => {
  let output;
  if (length > 100) {
    output = (Math.round(length / 1000 * 100) / 100) + ' km';
  } else {
    output = (Math.round(length * 100) / 100) + ' m';
  }
  return output;
};

const formatArea = (area) => {
  let output;
  if (area > 10000) {
    output = (Math.round(area / 1000000 * 100) / 100) + ' km<sup>2</sup>';
  } else {
    output = (Math.round(area * 100) / 100) + ' m<sup>2</sup>';
  }
  return output;
};

const formatAngle = (line) => {
  const coordinates = line.getCoordinates();
  let angle = '0°';
  if (coordinates.length === 3) {
    const proj = props.map.getView().getProjection();
    const disa = getLength(new LineString([coordinates[0], coordinates[1]]), { radius: 6378137, projection: proj });
    const disb = getLength(new LineString([coordinates[1], coordinates[2]]), { radius: 6378137, projection: proj });
    const disc = getLength(new LineString([coordinates[0], coordinates[2]]), { radius: 6378137, projection: proj });
    const cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb);
    angle = (Math.acos(cos) * 180) / Math.PI;
    angle = angle.toFixed(2);
  }
  return isNaN(angle) ? "0°" : angle + "°";
};

const stopMeasure = () => {
  tipDiv = null;
  if (draw.value) {
    props.map.removeInteraction(draw.value);
    draw.value = null;
  }
  const tipOverlay = props.map.getOverlayById("tipLay");
  if (tipOverlay) {
    props.map.removeOverlay(tipOverlay);
  }
};

const clearAllMeasurements = () => {
  if (vectorLayer.value) {
    vectorLayer.value.getSource().clear();
  }
  if (props.map) {
    // 创建一个副本进行迭代，因为在迭代时修改集合会导致问题
    const overlays = [...props.map.getOverlays().getArray()];
    overlays.forEach(overlay => {
      if (overlay.getId() !== "tipLay") {
        props.map.removeOverlay(overlay);
      }
    });
  }
  measureResult.value = "0";
  Object.keys(measurementResults).forEach(key => delete measurementResults[key]); // 清空 reactive 对象
  stopMeasure();
};

const clearMeasure = () => {
  if (vectorLayer.value) {
    vectorLayer.value.getSource().clear();
  }
  const overlays = [...props.map.getOverlays().getArray()];
  overlays.forEach(overlay => {
    const id = overlay.getId();
    if (id && id !== "tipLay" && (id.startsWith("close") || id.startsWith("length") || id.startsWith("area") || id.startsWith("angle"))) {
      props.map.removeOverlay(overlay);
    }
  });

  if (pointermoveEvent) unByKey(pointermoveEvent);
  if (geometryListener) unByKey(geometryListener);

  pointermoveEvent = null;
  geometryListener = null;
  measureResult.value = "0";
};

// 在组件卸载前执行清理
onBeforeUnmount(() => {
  clearAllMeasurements();
  if (props.map && vectorLayer.value) {
    props.map.removeLayer(vectorLayer.value);
  }
});
</script>

<style>
.measure-tool {
  z-index: 1000;
  position: absolute;
  right: 10px;
  top: 10px;
  width: 100px;
  height: 140px; /* 增加高度以适应第四个按钮 */
  background: white;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.button-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: 100%;
  position: relative;
}

/* 调整按钮定位 */
.distance-button {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
}

.area-button {
  position: absolute;
  top: 40px;
  left: 50%;
  transform: translateX(-50%);
}

.angle-button {
  position: absolute;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
}

.clear-button {
  position: absolute;
  top: 100px;
  left: 50%;
  transform: translateX(-50%);
}

.ol-control button {
  width: 80px; /* 统一按钮宽度 */
  padding: 8px;
  font-size: 14px;
  border: none;
  border-radius: 5px;
  background-color: #007bff;
  color: white;
  cursor: pointer;
}

.ol-control button:hover {
  background-color: #0056b3;
}
</style>